package com.mtung.dubbo.rpc;

import com.mtung.dubbo.RpcAnnotation;
import com.mtung.dubbo.handler.DubboServerHandler;
import com.mtung.dubbo.marshalling.MarshallingCodeCFactory;
import com.mtung.dubbo.register.ServiceRegister;
import com.mtung.dubbo.register.ServiceRegisterImpl;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * mtung 手写rpc调用框架服务端
 * @author : zhenguo.yao
 * @date : 2020/3/23 0023 15:14
 */
public class MtungRpcServer {

    private ServiceRegister serviceRegister;

    /**
     * host
     */
    private String host;
    /**
     * 端口号
     */
    private int port;

    private Map<String, Object> handlerMap = new HashMap<String, Object>();
    public MtungRpcServer(String host, int port) {
        this.host = host;
        this.port = port;
        serviceRegister = new ServiceRegisterImpl();
    }


    public void startServer(Object object) throws UnsupportedEncodingException {
        registerToZk(object);
        nettyStart();
    }

    /**
     * 注册到zookeeper
     * @param object
     * @throws UnsupportedEncodingException
     */
    private void registerToZk(Object object) throws UnsupportedEncodingException {
        final RpcAnnotation annotation = object.getClass().getAnnotation(RpcAnnotation.class);
        if(annotation == null){
            return;
        }
        // 获取类信息
        final String className = annotation.value().getName();
        String serviceAddress = "mtung://" + host + ":" + port;
        serviceRegister.register(className,serviceAddress);
        handlerMap.put(className,object);
    }

    /**
     * 启动netty 服务端
     */
    private void nettyStart(){
        final NioEventLoopGroup bossGroup = new NioEventLoopGroup();

        final NioEventLoopGroup workGroup = new NioEventLoopGroup();

        final ServerBootstrap serverBootstrap = new ServerBootstrap();

        serverBootstrap.group(bossGroup,workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                        ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                        ch.pipeline().addLast(new DubboServerHandler(handlerMap));
                    }
                });
        try {
            final ChannelFuture future = serverBootstrap.bind(port).sync();
            System.out.println("服务器启动成功：" + port);
            // 等待服务器监听端口
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 优雅的关闭连接
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

}
